package iohelper

import (
	"encoding/binary"
	"fmt"
	"io"
	"unsafe"
)

type ReadHelper struct {
	reader  io.Reader
	byteOrd binary.ByteOrder
	buff    []byte
}

func (r *ReadHelper) ReadBytes(n int) ([]byte, error) {
	var ret []byte
	if n > 0 {
		ret = make([]byte, n)
		l, err := r.reader.Read(ret)
		if err != nil {
			return ret, err
		}
		if l != n {
			return ret, fmt.Errorf("ReadBytes error %d, %d", l, n)
		}
	}
	return ret, nil
}

func (r *ReadHelper) ReadByte() (byte, error) {
	v, err := r.ReadUint8()
	return byte(v), err
}

func (r *ReadHelper) ReadInt8() (int8, error) {
	v, err := r.ReadUint8()
	return int8(v), err
}

func (r *ReadHelper) ReadInt16() (int16, error) {
	v, err := r.ReadUint16()
	return int16(v), err
}

func (r *ReadHelper) ReadInt32() (int32, error) {
	v, err := r.ReadUint32()
	return int32(v), err
}

func (r *ReadHelper) ReadInt64() (int64, error) {
	v, err := r.ReadUint64()
	return int64(v), err
}

func (r *ReadHelper) ReadUint8() (v uint8, err error) {
	var buff [1]byte
	v = 0
	n, err := r.reader.Read(buff[:1])
	if n == 1 {
		v = uint8(buff[0])
	}
	return v, err
}

func (r *ReadHelper) ReadUint16() (v uint16, err error) {
	var buff [2]byte
	v = 0
	sz := unsafe.Sizeof(v)
	n, err := r.reader.Read(buff[:sz])
	if n == int(sz) {
		v = uint16(r.byteOrd.Uint16(buff[:sz]))
	}
	return v, err
}

func (r *ReadHelper) ReadUint32() (v uint32, err error) {
	var buff [4]byte
	v = 0
	sz := unsafe.Sizeof(v)
	n, err := r.reader.Read(buff[:sz])
	if n == int(sz) {
		v = uint32(r.byteOrd.Uint32(buff[:sz]))
	}
	return v, err
}

func (r *ReadHelper) ReadUint64() (v uint64, err error) {
	var buff [8]byte
	v = 0
	sz := unsafe.Sizeof(v)
	n, err := r.reader.Read(buff[:sz])
	if n == int(sz) {
		v = uint64(r.byteOrd.Uint64(buff[:sz]))
	}
	return v, err
}

func (r *ReadHelper) Read(p []byte) (n int, err error) {
	return r.reader.Read(p)
}

// 读取 delphi 的 string[n] 字符串,
func (r *ReadHelper) ReadShortStr(shrtSize int) (string, error) {
	var bs []byte
	l, err := r.ReadUint8()
	if err != nil {
		return "", err
	}

	if l > 0 {
		bs = make([]byte, l)
		n, err := r.reader.Read(bs)
		if err != nil {
			return "", err
		}
		if n == int(l) {
			// ok
		} else {
			return "", fmt.Errorf("ReadShortStr, read len is too small")
		}
	}

	if shrtSize > int(l) {
		n := shrtSize - int(l)
		v, err := io.CopyN(io.Discard, r.reader, int64(n))
		if err != nil {
			return "", err
		}
		if int(v) != n {
			return "", fmt.Errorf("ReadShortStr: discard n failed: %d <> %d", v, n)
		}
	}

	return string(bs), nil
}

func (r *ReadHelper) DiscardN(n int64) (int64, error) {
	return io.CopyN(io.Discard, r.reader, n)
}

// 读消息头，分隔符, 最大支持8个字节
func (r *ReadHelper) ReadMsgSignature(singnValue int64, valueSize int) (ret int, err error) {
	values := make([]byte, valueSize)
	switch valueSize {
	case 1:
		values[0] = byte(singnValue)
	case 2:
		r.byteOrd.PutUint16(values, uint16(singnValue))
	case 4:
		r.byteOrd.PutUint32(values, uint32(singnValue))
	case 8:
		r.byteOrd.PutUint64(values, uint64(singnValue))
	default:
		return 0, fmt.Errorf("不支持的类型大小: %d", valueSize)
	}
	return r.ReadMsgSignatureBytes(values)
}

// 读消息头，分隔符, 最大支持8个字节
func (r *ReadHelper) ReadMsgSignatureBytes(values []byte) (ret int, err error) {
	valueSize := len(values)
	bufLen := len(r.buff)
	var readIdx, writeIdx, currLen int
	var v byte
	for {
		v, err = r.ReadByte() // 每次只能读了个字节
		if err != nil {
			break
		}
		ret++
		if writeIdx == 0 && v != values[0] { // 还没开始写入，第一个就匹配不上，直接跳过，减少复制
			continue
		}
		// if writeIdx >= bufLen {
		// 	panic("这里为啥出错？" + strconv.Itoa(writeIdx) + ", " + strconv.Itoa(readIdx) + ", sz = " + strconv.Itoa(valueSize) +
		// 		", buflen = " + strconv.Itoa(bufLen) + ", currLen = " + strconv.Itoa(currLen))
		// }
		r.buff[writeIdx] = v
		writeIdx++

		currLen = writeIdx - readIdx
		if currLen < valueSize {
			if writeIdx >= bufLen { // 已经写满了
				if currLen > 0 {
					copy(r.buff[:currLen], r.buff[readIdx:writeIdx])
					readIdx = 0 // 从头开始
					writeIdx = currLen
				} else {
					readIdx = 0 // 从头开始
					writeIdx = 0
				}
			}
		} else { // currLen == valueSize
			cnt := 0 // 匹配的数量
			for i := 0; i < valueSize; i++ {
				if r.buff[readIdx+i] == values[i] {
					cnt++
					if cnt >= valueSize { // 匹配上了
						return ret, nil
					}
				} else {
					readIdx++
					break
				}
			}
			for readIdx < writeIdx { // 只比较第一个，快速跳过
				if r.buff[readIdx] != values[0] {
					readIdx++
				} else {
					break
				}
			}
			if readIdx >= writeIdx { // 所有都匹配不上，从头开始，减少复制
				writeIdx = 0
				readIdx = 0
			}
		}
	}
	return ret, err
}

// 读取动态长度
func (r *ReadHelper) ReadDynLen() (ret uint64, err error) {
	return ReadDynLen(r)
}

// 读取动态长度字符串
func (r *ReadHelper) ReadString() (ret string, err error) {
	var l uint64
	l, err = r.ReadDynLen()
	if err != nil {
		return
	}
	bits := make([]byte, l)
	_, err = r.Read(bits)
	if err != nil {
		return
	}
	return string(bits), err
}

// 第二个参数可以传大小端，为空时使用小端
func NewReadHelper(reader io.Reader, byteOrd binary.ByteOrder) *ReadHelper {
	if byteOrd == nil {
		byteOrd = binary.LittleEndian
	}
	return &ReadHelper{reader: reader, byteOrd: byteOrd, buff: make([]byte, 32, 32)} // 32 字节作缓存
}
